#include "dealpicturethread.h"
#include <QCryptographicHash>  //md5加密的库
#include <QBuffer>
#include <QDebug>
#include <QThread>
#include <QtMath>
#include <QImage>
#include <QPainter>
#include <QFile>
#include <QProcess>
#include <QPen>
#include <algorithm>
#include <stdio.h>
#include <pthread.h>
#include "./beans/systemconfig.h"

DealSmallPictureThread::DealSmallPictureThread(QObject* parent):QObject(parent)
{
    m_Thread = new std::thread(&DealSmallPictureThread::run,this);
    pthread_t thread_id = m_Thread->native_handle();
    // 设置线程名称（限制为16个字符）
    int result = pthread_setname_np(thread_id, "smallPicThread");
    if (result != 0) {
        qDebug() << "设置线程名称有错误！";
    }
    m_Thread->detach();
}

DealSmallPictureThread::~DealSmallPictureThread(){
    if(!m_Thread->joinable()){
        delete m_Thread;
        m_Thread = NULL;
    }
}

void DealSmallPictureThread::run(){
    while(1){
        std::unique_lock<std::mutex> lock(m_Mutex);
        if(m_MsgQueue.size() <= 0){
            is_Waiting = true;
        }
        m_Condition.wait(lock,[&]{ return m_MsgQueue.size() > 0;});

        SmallPic_Struct* picInfo = m_MsgQueue.front();
        QByteArray imageBytes;
        QBuffer buffer;
        buffer.open(QIODevice::WriteOnly);

        picInfo->image.save(&buffer,"png",20);
        imageBytes.append(buffer.data());
        QString uuid;
        QByteArray str;
        str = QCryptographicHash::hash(imageBytes,QCryptographicHash::Md5);
        uuid.append(str.toHex());

        m_PicMd5Str[m_CurPath+picInfo->id] = uuid;

        QString path=QString("/mnt/nvme/qmlPrint/%1.png").arg(uuid);
        picInfo->image.save(path,"TIF",10);

        emit onPicCompleted(m_PicMd5Str);
        emit onDealCompleted();

        m_MsgQueue.pop(); 
    }
}

void DealSmallPictureThread::doMessageAccepted(SmallPic_Struct* picInfo){
    std::unique_lock<std::mutex> lock(m_Mutex);
    m_MsgQueue.push(picInfo);

    if(is_Waiting){
        m_Condition.notify_all();
        is_Waiting = false;
    }
}

void DealSmallPictureThread::doCurrentFolderPicInfo(const QString& curPath){
    m_CurPath = curPath+"/";
}

/*****************************************************/
#define _ITEMS(a)       (sizeof(a)/sizeof(a[0]))
DealBigPictureThread::DealBigPictureThread(QObject* parent):QObject(parent),
    m_PaperWidth(SystemConfig::getInstance()->value("setting/paperwidth","330").toString())
{
    m_Thread = new std::thread(&DealBigPictureThread::run,this);
    pthread_t thread_id = m_Thread->native_handle();
    int result = pthread_setname_np(thread_id, "bingPackThread");
    if (result != 0) {
        qDebug() << "设置线程名称有错误！";
    }
    m_Thread->detach();
}

DealBigPictureThread::~DealBigPictureThread(){
    if(!m_Thread->joinable()){
        delete m_Thread;
        m_Thread = NULL;
    }
}

void DealBigPictureThread::run(){
    while(1){
        std::unique_lock<std::mutex> lock(m_Mutex);
        if(m_MsgQueue.size() <= 0){
            is_Waiting = true;
        }
        m_Condition.wait(lock,[&]{ return m_MsgQueue.size() > 0;});

        const QVariantList& list = m_MsgQueue.front();

        int jobCount = list.size(); //作业数
        int allPosCount = 0;

        QList<QString> filesList = {};
        QList<int> fileJobIndex = {};
        QList<double> scaleList = {}; //相对于之前的图的缩放比例
        double paperHeight = 0;
        //自动排版
        if(isAutoBingPack){
            PackingParam p;
            p.Width     = m_PaperWidth.toDouble();
            p.Height    = 100000.00; //100米
            p.Count     = jobCount;
            p.Algorithm = PackingAlgorithm::PA_MAX_RECTS_BSSF_BBF ;   //PA_SHELF_NF_BNF_USE_WASTE;
            p.AllowFlip = true;   //允许图片旋转排版
            p.IntervalX = m_PicGap; //x方向间隔
            p.IntervalY = m_PicGap; //y方向间隔
            PackingJob jobs[jobCount];
            PackingImageInfo imageInfo[jobCount];

            for(int i = 0 ; i < list.size() ; i++){
                int copy = list.at(i).toMap()["copy"].toInt();
                //统计总的pos个数
                allPosCount += copy;
                jobs[i].Copies = copy;

                int rotation = list.at(i).toMap()["rotation"].toInt();
                if(0 == rotation || 180 == rotation)
                {
                    jobs[i].Width = list.at(i).toMap()["width"].toDouble();
                    jobs[i].Height = list.at(i).toMap()["height"].toDouble();
                    scaleList.push_back(list.at(i).toMap()["width"].toDouble()*1.0 / list.at(i).toMap()["initWidth"].toDouble());
                }else{
                    jobs[i].Width = list.at(i).toMap()["height"].toDouble();
                    jobs[i].Height = list.at(i).toMap()["width"].toDouble();
                    scaleList.push_back(list.at(i).toMap()["height"].toDouble()*1.0 / list.at(i).toMap()["initWidth"].toDouble());
                }
            }
            //设置总的 pos 位置数目
            PackingPos packPos[allPosCount];
            p.Pos = packPos;
            p.ImageInfo = imageInfo;
            p.Jobs = jobs;

            if(RectangleBinPacking(&p)){
                int allPosArrayCount = (int)p.PosCount;
                MtPackTransformImage  imgIn[allPosArrayCount];
                QVariantList tempAutoPackList = {};

                if(allPosArrayCount > 0){
                    for(int i = 0 ; i < allPosArrayCount ; i++){
                          imgIn[i].width  = list.at(packPos[i].JobIndex).toMap()["initWidth"].toDouble();
                          imgIn[i].height = list.at(packPos[i].JobIndex).toMap()["initHeight"].toDouble();
                          imgIn[i].xdpi   = list.at(packPos[i].JobIndex).toMap()["xDpi"].toDouble();
                          imgIn[i].ydpi   = list.at(packPos[i].JobIndex).toMap()["yDpi"].toDouble();
                          imgIn[i].loc    = {packPos[i].X, packPos[i].Y};
                          imgIn[i].scale  = scaleList[packPos[i].JobIndex];

                          QVariantMap tempMap;
                          int rotation = list.at(packPos[i].JobIndex).toMap()["rotation"].toInt();
                          if(packPos[i].IsRotate){
                               imgIn[i].rot  = 90.0;

                               if(0 == rotation || 180 == rotation ){
                                   tempMap["width"] = list.at(packPos[i].JobIndex).toMap()["height"].toDouble();
                                   tempMap["height"] = list.at(packPos[i].JobIndex).toMap()["width"].toDouble();
                                   tempMap["isRotate"] = true;
                               }else{
                                   tempMap["width"] = list.at(packPos[i].JobIndex).toMap()["width"].toDouble();
                                   tempMap["height"] = list.at(packPos[i].JobIndex).toMap()["height"].toDouble();
                                   tempMap["isRotate"] = false;
                               }
                               tempMap["rotation"] = 90;
                          }else{
                              imgIn[i].rot  = 0.0;

                              if(0 == rotation || 180 == rotation ){
                                  tempMap["width"] = list.at(packPos[i].JobIndex).toMap()["width"].toDouble();
                                  tempMap["height"] = list.at(packPos[i].JobIndex).toMap()["height"].toDouble();
                                  tempMap["isRotate"] = false;
                              }else{
                                  tempMap["width"] = list.at(packPos[i].JobIndex).toMap()["height"].toDouble();
                                  tempMap["height"] = list.at(packPos[i].JobIndex).toMap()["width"].toDouble();
                                  tempMap["isRotate"] = true;
                              }
                              tempMap["rotation"] = 0;
                          }

                          tempMap["x"] = packPos[i].X;
                          tempMap["y"] = packPos[i].Y;
                          tempMap["jobIndex"] = packPos[i].JobIndex;
                          tempMap["fileName"] = list.at(packPos[i].JobIndex).toMap()["filePath"].toString();

                          tempAutoPackList.push_back(tempMap);
                          fileJobIndex.push_back(packPos[i].JobIndex);
                    }

                    double finalPaperWidth = [&]{
                        if(p.Width > m_PaperWidth.toDouble())
                            return m_PaperWidth.toDouble();
                        else
                            return p.Width;
                    }();

                    MtPackTransformParam  param   = {
                        .images     = imgIn,
                        .imageCount = _ITEMS(imgIn),
                        .paper      = {
                          .width    = finalPaperWidth,
                          .height   = p.Height,
                          .xdpi     = 600.,
                          .ydpi     = 600.,
                        },
                    };

                    //完成仿射坐标转换
                    auto ret = MtPackTransform(&param);
                    if(ret)
                    {
                        emit onDealBingPack(ret,fileJobIndex);
                        emit onDealAutoPackList(tempAutoPackList);
                    }
                    std::this_thread::sleep_for(std::chrono::milliseconds(100));
                }
                paperHeight = p.Height;
            }

            emit onDealAutoPackCompleted(); //自动排版结束信号
            emit onDealPaperHeight(paperHeight);
        }else{
            //固定排版
            allPosCount = m_PackList.size();

            MtPackTransformImage  imgInFixed[allPosCount];
            for(int i = 0 ; i < allPosCount ; i++){
                  imgInFixed[i].width  = m_PackList.at(i).toMap()["initWidth"].toDouble();
                  imgInFixed[i].height = m_PackList.at(i).toMap()["initHeight"].toDouble();
                  imgInFixed[i].xdpi   = m_PackList.at(i).toMap()["xDpi"].toDouble();
                  imgInFixed[i].ydpi   = m_PackList.at(i).toMap()["yDpi"].toDouble();
                  imgInFixed[i].loc    = {m_PackList.at(i).toMap()["x"].toDouble(), m_PackList.at(i).toMap()["y"].toDouble()};
                  imgInFixed[i].scale  = m_PackList.at(i).toMap()["scale"].toDouble();

                  if(m_PackList.at(i).toMap()["isRotate"].toBool())
                      imgInFixed[i].rot      = 90.;
                  else
                      imgInFixed[i].rot      = 0.;

                  fileJobIndex << m_PackList.at(i).toMap()["jobIndex"].toInt();
            }

            MtPackTransformParam  param   = {
                .images     = imgInFixed,
                .imageCount = _ITEMS(imgInFixed),
                .paper      = {
                  .width    = m_PaperWidth.toDouble(),
                  .height   = m_ViewHeight,
                  .xdpi     = 600.,
                  .ydpi     = 600.,
                },
            };

            //完成仿射坐标转换
            auto ret = MtPackTransform(&param);
            if(ret)
            {
                emit onDealBingPack(ret,fileJobIndex);
            }

            std::this_thread::sleep_for (std::chrono::milliseconds(50));
            //固定排版结束信号
            emit onDealFixedPackCompleted();
        }

        m_MsgQueue.pop();
    }
}

void DealBigPictureThread::doMessageAccepted(QVariantList& msg){
    std::unique_lock<std::mutex> lock(m_Mutex);
    m_MsgQueue.push(msg);

    if(is_Waiting){
        m_Condition.notify_all();
        is_Waiting = false;
    }
}

void DealBigPictureThread::doSetPaperWidth(const QString& width){
    m_PaperWidth = width;
}

void DealBigPictureThread::doBingPack(const bool& b){
    isAutoBingPack = b;
}

void DealBigPictureThread::doPicGap(const double& gap){
    m_PicGap = gap;
}

void DealBigPictureThread::doDealPackList(const QVariantList& list,const double& viewHeight){
    m_PackList = list;
    m_ViewHeight = viewHeight;
}
